﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.Windows;
using System.IO;
using System.Xml.Linq;
using System.Xml;
using System.Diagnostics;

namespace wiki2doc
{
    [Export(typeof(IGenerateDocument))]
    [ExportMetadata("Type","chm")]
    [ExportMetadata("MenuText", "Generate Windows HTML Help File (.chm)")]
    public class GenerateCHM : IGenerateDocument
    {
        [Import("StatusMessage")]
        Action<string> StatusMessage;
        
        private string prv_workfolder;

        public GenerateCHM()
        {
            prv_workfolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Temp\wiki2doc";
        }

        public void Generate(List<string> topics, IConfiguration configuration, string templatePath)
        {
            StatusMessage("Generate CHM");
            
            var tp = configuration.TemplatePath;
            if (tp == "") tp = templatePath;

            PrepareTargetFolder(tp);

            CopyImagesFromSource();

            TransformTopics(topics, tp);

            // generate hhc and hhp files
            GenerateHHP();
            GenerateHHC();

            var filename = BuildCHM(configuration);

            StatusMessage("CHM generated in: " + filename);
        }

        private string BuildCHM(IConfiguration configuration)
        {
            string filename = "<no file>";
            StatusMessage("Building CHM");
            // TODO: Building CHM
            return filename;
        }

        private void GenerateHHC()
        {
            // TODO: GenerateHHC
        }

        private void GenerateHHP()
        {
            // TODO: GenerateHHP
        }

        private void TransformTopics(List<string> topics, string templatePath)
        {
            StatusMessage("Transform topics");
            var content = new XmlDocument(  );
            var wf = prv_workfolder + @"\target";
            var wf_src = prv_workfolder + @"\source";

            foreach( var topic in topics )
            {
                StatusMessage("Transforming topic '" + topic + "'");
                

                var fn_src = wf_src + @"\xhtml\" + topic.Replace(":", "-") + ".html";

                content.Load(fn_src);

                var nsmgr = new XmlNamespaceManager(content.NameTable);
                nsmgr.AddNamespace("x", content.DocumentElement.NamespaceURI);

                var body = content.SelectSingleNode("//x:body", nsmgr);

                
                // Remove 'Back to start' links (aka links with start in name)
                var l = content.SelectNodes("//x:body//x:p", nsmgr);
                foreach ( XmlNode i in l )
                {
                    var l2 = i.SelectNodes("//x:a[@class='wikilink1']", nsmgr);
                    foreach( XmlNode ii in l2 )
                    {
                        if ( ii.InnerText.Contains("Back to") )
                        {
                            body.RemoveChild(i);
                        }
                    }
                }
                
                
                // Replace all media anchors containing a image tag
                l = content.SelectNodes("//x:a[@class='media']", nsmgr);
                foreach ( XmlNode i in l )
                {
                    // got a href attribute?
                    if ( i.Attributes.GetNamedItem("href")  != null )
                    {
                        XmlNode pic = i.FirstChild;
                        XmlNode pi = i.ParentNode;

                        XmlElement elem = content.CreateElement("img");

                        // Add the node to the document.
                        pi.InsertAfter(elem, i.PreviousSibling);

                        int pos;
                        string fn = pic.Attributes.GetNamedItem("src").InnerText;

                        fn = fn.Substring( fn.LastIndexOf("/") );
                        if ( fn.Contains("?") )
                        {
                            fn = fn.Substring(0, fn.IndexOf("?"));
                        }

                        elem.SetAttribute("src", @"images/" + fn);
                        elem.SetAttribute("class", pic.Attributes.GetNamedItem("class").InnerText);

                        if ( pic.Attributes.GetNamedItem("alt") != null )
                            elem.SetAttribute("alt", pic.Attributes.GetNamedItem("alt").InnerText);

                        if ( pic.Attributes.GetNamedItem("title") != null )
                            elem.SetAttribute("title", pic.Attributes.GetNamedItem("title").InnerText);

                        if (pic.Attributes.GetNamedItem("width") != null)
                            elem.SetAttribute("width", pic.Attributes.GetNamedItem("width").InnerText);

                        pi.RemoveChild(i);

                    }
                
                }
                
                // alter images with no anchor ( &nolink items )
                l = content.SelectNodes("//x:img[@class='media']", nsmgr);
                foreach ( XmlNode i in l )
                {
                    // got a href attribute?
                    if ( i.Attributes.GetNamedItem("src") != null )
                    {
                        var fn = i.Attributes.GetNamedItem("src").InnerText;
                        if ( fn.StartsWith("/_media") )
                        {
                            fn = fn.Substring( fn.LastIndexOf("/") );
                            if ( fn.Contains("?") )
                            {
                                fn = fn.Substring(0, fn.IndexOf("?"));
                            }
                            i.Attributes.GetNamedItem("src").InnerText = @"images/" + fn;
                        }
                    }
                }

                
                // replace smiley links
                l = content.SelectNodes("//x:img[@class='icon']", nsmgr);
                foreach ( XmlNode i in l )
                {
                    if ( i.Attributes.GetNamedItem("src").InnerText.StartsWith("/lib/images/smileys") )
                    {
                        Debug.WriteLine("system image: " + i.Attributes.GetNamedItem("alt").InnerText);

                        var nm = System.IO.Path.GetFileName(i.Attributes.GetNamedItem("src").InnerText);
                        var fn = @"images/" + nm;

                        if ( ! File.Exists(Path.Combine(wf, "html", "images", nm)) )
                        {
                            // copy image from template dir
                            File.Copy(
                                Path.Combine(templatePath, "Images", "smileys", nm),
                                Path.Combine(wf, "html", "images", nm)
                                );
                        }

                        i.Attributes.GetNamedItem("src").InnerText = fn;

                    }
                }
                
                // Replace internal links
                l = content.SelectNodes("//x:a[@class='wikilink1']", nsmgr);
                foreach ( XmlNode i in l )
                {
                   
                    var href = i.Attributes.GetNamedItem("href").InnerText;
                    
                    if ( !href.Contains("#") )
                        href += "#";
                    var arr = href.Split('#');
                
                    href = Path.GetFileNameWithoutExtension(arr[0]) + ".html";
                    if ( arr[1] != "" )
                        href += "#" + arr[1];
                    
                    i.Attributes.GetNamedItem("href").InnerText = href;
                }
                
                File.WriteAllText(wf + @"\html\" + topic.Replace(":", "-") + ".html", content.OuterXml, Encoding.UTF8);
                
            }

        }

        private void CopyImagesFromSource()
        {
            StatusMessage("Copy images");
            // copy images to correct location
            var wf = prv_workfolder + @"\target";
            var wf_src = prv_workfolder + @"\source";
            DirFile.CopyFolder(wf_src + @"\images", wf + @"\html\images");
        }

        private void PrepareTargetFolder(string templatePath)
        {
            StatusMessage("Prepare target folders");

            var wf = prv_workfolder + @"\target";
            // clear work folder
            try
            {
                Directory.Delete(wf, true);
            }
            catch (Exception)
            {
                // nothing to delete
            }

            // create folder structure
            Directory.CreateDirectory(wf);
            Directory.CreateDirectory(wf + @"\html");
            Directory.CreateDirectory(wf + @"\html\images");
            
            // copy stylesheet(s)
            DirFile.CopyFiles(templatePath + @"\Styles", wf + @"\html", "*.css");

        
        }
    }
}
